/*
 * -----------------------------------------------------------------------------
 * Project  : MS Message Queue Support
 * Purpose  : Provide support for a base class message queue. Here definitions
 *          : for the base mess-queue class will be provided. I selected to use
 *          : the message-queue API to have the ability to access all MSMQ
 *          : functionality. The provided MSMQ object looks fine still lack of
 *          : access to internals may be a problem on some projects.
 * File     : Win32.Net.Msmq.cpp
 * Author   : Eduardo Sobrino
 * Date     : Aug/1998
 * Updated  : Jun/2007  (Added code to Kif framework)
 */

#pragma once

#pragma region   // Include Files

#include <windows.h>
#include <mq.h>
#include "Win32.String.h"

#pragma endregion

// -----------------------------------------------------------------------------

namespace Kif
{
namespace Win32
{
namespace Net
{
namespace Msmq
{

// -----------------------------------------------------------------------------
#pragma region   // Definces and Enumerators

#define DEFAULT_QUEUE_TIMEOUT 1000

#define MAX_VAR       20
#define MAX_FORMAT   100
#define MAX_NAMELEN   50

#define Q_OPEN   'O'
#define Q_CLOSE  'C'

enum MsmqStatus
{
   MsmqStatus_OK            =  0,
   MsmqStatus_CANTCREATE    =  1,
   MsmqStatus_CANTRETFNAME  =  2,
   MsmqStatus_CANTRETGNAME  =  3,
   MsmqStatus_QEXISTS       =  4,
   MsmqStatus_OPENRETRY     =  5,
   MsmqStatus_CANTROPEN     =  6,
   MsmqStatus_CANTSOPEN     =  7,
   MsmqStatus_RETRYROPENF   =  8,
   MsmqStatus_NEEDPATH      =  9,
   MsmqStatus_NEEDFORMAT    = 10,
   MsmqStatus_ERECEIVING    = 11,
   MsmqStatus_CANTDELETE    = 12,
   MsmqStatus_NOQREGISTERED = 13,
   MsmqStatus_ELOCBEGIN     = 14,
   MsmqStatus_ELOCNEXT      = 15,
   MsmqStatus_CANTSEND      = 16,
   MsmqStatus_INVQUEUEID    = 17,
   MsmqStatus_ALREADYCONN   = 18,
   MsmqStatus_NOMSMQSUPPORT = 19,
   MsmqStatus_QUEUENOTOPEN  = 20,
   MsmqStatus_BADMESSFORMAT = 21,
   MsmqStatus_ACCESSDENIED  = 22,
   MsmqStatus_OPRANOTSUPP   = 23,
   MsmqStatus_QUEUENOTFOUND = 24,
   MsmqStatus_BADMEMADDR    = 25
}  ;  // end of MsmqStatus

extern void MsmqStatusToString(MsmqStatus insts,TCHAR *obuff,int mlen);

#pragma endregion
// -----------------------------------------------------------------------------
#pragma region   // Declare MsmqQueue class

class MsmqQueue
{
   private:
      HRESULT     last_hr;
      QUEUEHANDLE queueHandle;        // queue handle
      HANDLE      queueCursor;        // queue cursor
      HANDLE      pHandle;            // cursor handle for peeking...

      DWORD dwPeekAction;             // Peek at first msg.
      DWORD dwReceiveAction;          // Receive action.

      WCHAR wcsPathName[MAX_PATH+1];    // queue pathname
      WCHAR wcsFormat[MAX_FORMAT+1];    // queue format
      WCHAR wcsAdminFormat[MAX_FORMAT+1];// admin queue format

      DWORD dwFormatNumChars;         // format num of unicode chars

      void SetMachineName();          // set machine name if not given

   public:

      MsmqStatus Status;              // last status return code
      CLSID  QueueGuid;                   // queue's unique identifier

      int    Retries;                 // default number of retries
      long   OpenTimeout;             // default timeout while opening queue
      DWORD  DefaultTimeout;          // default timeout
      DWORD  RecTimeout;              // default receive timeout

      BOOL   GetAcknowledgements;     // TRUE to request receiving acknowledgements
      BOOL   UseDeadLetter;           // TRUE to request sending to dead-letter queue
      BOOL   UseJournal;              // TRUE to request journaling
      bool   MTSTransactional;        // true for MTS transactional

      HRESULT LastHResult;            // always remember last result-handle

      TCHAR *pcMachineName;

      MsmqQueue();
     ~MsmqQueue();

      BOOL   Init();
      inline long GetLastHResult() { return((long)last_hr); }

      void   SetFormat(WCHAR *format,DWORD flen);
      void   SetFormat(TCHAR *format,int flen);

      void   InquireFormat(TCHAR *pFormat,int flen);
      inline WCHAR *InquireFormat() { return(wcsFormat); }
      inline WCHAR *InquireAdminQueueFormat() { return(wcsAdminFormat); }
      DWORD  InquireFormatNumChars() { return(dwFormatNumChars); }
      BOOL   InquireMachineGUID(TCHAR *wszMachineGuid,int buffSize);
      BOOL   InquireDeadLetterFormat(WCHAR *dlFormat,int buffSize);

      MsmqStatus PathToFormat();
      MsmqStatus PathToFormat(WCHAR *wFormat,char *path);
      MsmqStatus PathToFormat(WCHAR *wFormat,WCHAR *wPath);

      void   SetMachineName(TCHAR *pmachine);
      void   SetAdminQueueFormat(TCHAR *aformat,int buffSize);

      BOOL   SetQueuePathName(TCHAR *qname);
      BOOL   SetQueueFullPathName(TCHAR *fpath);
      BOOL   SetQueuePathName(TCHAR *rmachine,TCHAR *qname);
      BOOL   IsConnected() { return(queueHandle ? TRUE : FALSE); }

      BOOL   Create(CLSID &guid,TCHAR *qname,TCHAR *descript);
      BOOL   Create(TCHAR *pHost,TCHAR *pQueue,TCHAR *pDescript);
      BOOL   Create(TCHAR *qname,TCHAR *descript);
      BOOL   Create(TCHAR *pDescript);

      BOOL   Locate(CLSID &guid);
      inline BOOL Locate() { return(Locate(QueueGuid)); }

      BOOL   OpenToReceive(TCHAR *qname,long wmsec,int retries);
      BOOL   OpenToReceive(WCHAR *format,DWORD flen);
      BOOL   OpenToReceive(long wmsec,int retries);
      BOOL   OpenToReceive();
      BOOL   OpenToReceive(TCHAR *qname)
      { return(OpenToReceive(qname,OpenTimeout,Retries)); }

      BOOL   OpenToReceiveWithFormat(TCHAR *pFormat);
      BOOL   OpenToReceiveWithFormat()
      { return(OpenToReceive(wcsFormat,dwFormatNumChars)); }

      BOOL   OpenToSend(WCHAR *wFormat);
      BOOL   OpenToSendWithQueueName(TCHAR *qname);
      BOOL   OpenToSend(TCHAR *rmachine,TCHAR *qname);
      inline BOOL OpenToSend()
      { Status = PathToFormat(wcsFormat,wcsPathName);
        return(OpenToSend(wcsFormat)); }
      BOOL   OpenToSendWithFormat(TCHAR *pFormat,int buffSize);
      inline BOOL OpenToSendWithFormat()
      { return(OpenToSend(wcsFormat)); }

      BOOL   OpenToPeek(WCHAR *wFormat);
      BOOL   PeekMessage(TCHAR *lbl,int mllen,TCHAR *buff,int mblen);
      BOOL   PeekCurrentMessage(TCHAR *lbl,int mllen,TCHAR *buff,int mblen);
      BOOL   ReadMessage(TCHAR *lbl,int mllen,TCHAR *buff,int mblen);

      BOOL   ReceiveMessage(TCHAR *lbl,int mllen,TCHAR *buff,int mblen);
      BOOL   ReceiveMessage(TCHAR *buff,int mblen);

      BOOL   SendMessage(TCHAR *lbl,TCHAR *buff,int mblen);
      BOOL   SendMessage(TCHAR *buff,int mblen);

      inline void Close()
      {
          if (queueHandle)
             MQCloseQueue(queueHandle);
          queueHandle = NULL;
          if (pHandle)
             MQCloseCursor(pHandle);
          pHandle = NULL;
      }

      BOOL   Delete();
      BOOL   Delete(TCHAR *qname);
      BOOL   Delete(TCHAR *pHost,TCHAR *pQueue);
      bool   Opened() { return(queueHandle != NULL); }
}  ;  // end of MsmqQueue

#pragma endregion
// -----------------------------------------------------------------------------
#pragma region   // Declare MsmqSettings class

class MsmqSettings
{
   public:

   Kif::Win32::String Description;  // queue description
   Kif::Win32::String HostName;     // host name
   Kif::Win32::String QueueName;    // queue name

   WCHAR  FormatName[MAX_FORMAT+1];    // format path
   DWORD  FormatNameLength;            // format length
   TCHAR  Status;                      // status char
   BOOL   OutQueueOnly;                // TRUE when this is an output-queue
   long   ReadTimeOut;                 // read timetout
   bool   IsTrasactional;              // true if MTS transactional...

   void   Init();
   BOOL   Init(MsmqQueue *queue);
   BOOL   Init(MsmqQueue *queue,TCHAR *pFormatName);
   BOOL   InitAndOpenToSend(MsmqQueue *queue,TCHAR *pFormatName);

   BOOL   OpenToSend(MsmqQueue *queue);

   void   GetErrorString(TCHAR *pErrString,int errStrLen,
             TCHAR *pMess,MsmqQueue *queue);
   void   GetErrorString(TCHAR *pErrString,int errStrLen,MsmqQueue *queue);

   MsmqSettings() { Init(); }

}  ;  // end of MsmqSettings

#pragma endregion
// -----------------------------------------------------------------------------

}  // end of Kif::Win32::Net::Msmq
}  // end of Kif::Win32::Net
}  // end of Kif::Win32
}  // end of Kif


